<cfcomponent displayname="fifoCache" output="false" namespace="org.rickosborne.util" hint="First-In-First-Out Cache">
	<cfset this.Cache=StructNew()>
	<cfset this.History=ArrayNew(1)>
	<cfset this.MaxSize=100>
	<cfset this.GUID=CreateUUID()>
	<cffunction name="init" displayname="init" output="false" description="Initialize our object" returntype="fifoCache">
		<cfargument name="MaxSize" required="false" type="numeric">
		<cfif StructKeyExists(Arguments, "MaxSize") AND IsNumeric(Arguments.MaxSize) AND (Arguments.MaxSize GT 0)>
			<cfset this.MaxSize=Arguments.MaxSize>
		</cfif>
		<cfset this.GUID=CreateUUID()>
		<cfreturn this>
	</cffunction>
	<cffunction name="Get" displayname="Get" output="false" description="Get an item from the cache" returntype="any">
		<cfargument name="Key" required="true" type="string">
		<cfset var ret="">
		<cflock name="#this.GUID#" type="READONLY" timeout="5" throwontimeout="false">
			<cfif StructKeyExists(this.Cache,Arguments.Key)>
				<cfset ret=this.Cache[Arguments.Key]>
			</cfif>
		</cflock>
		<cfreturn ret>
	</cffunction>
	<cffunction name="Put" displayname="Put" output="false" description="Put an item into the cache" returntype="numeric">
		<cfargument name="Key" required="true" type="any">
		<cfargument name="Value" required="false" type="any" default="">
		<cfset var ret=0>
		<cfset var i=0>
		<cflock name="#this.GUID#" type="EXCLUSIVE" timeout="5" throwontimeout="false">
			<cfif StructKeyExists(this.Cache,Arguments.Key)>
				<cfloop from="#ArrayLen(this.History)#" to="1" step="-1" index="i">
					<cfif this.History[i] EQ Arguments.Key>
						<cfset ArrayDeleteAt(this.History, i)>
					</cfif>
				</cfloop>
			</cfif>
			<cfset this.Cache[Arguments.Key]=Arguments.Value>
			<cfset ArrayAppend(this.History,Arguments.Key)>
			<cfloop condition="(ArrayLen(this.History) GT 0) AND (ArrayLen(this.History) GT this.MaxSize)">
				<cfset StructDelete(this.Cache, this.History[1])>
				<cfset ArrayDeleteAt(this.History, 1)>
			</cfloop>
			<cfset ret=ArrayLen(this.History)>
		</cflock>
		<cfreturn ret>
	</cffunction>
	<cffunction name="Exists" displayname="Exists" output="true" description="Find an item in the cache" returntype="boolean">
		<cfargument name="Key" required="true" type="string">
		<cfset var ret=false>
		<cflock name="#this.GUID#" type="READONLY" timeout="5" throwontimeout="false">
			<cfset ret=StructKeyExists(this.Cache,Arguments.Key)>
		</cflock>
		<cfreturn ret>
	</cffunction>
	<cffunction name="Delete" displayname="Delete" output="false" description="Delete an item from the cache" returntype="numeric">
		<cfargument name="Key" required="true" type="string">
		<cfset var ret=0>
		<cfset var i=0>
		<cflock name="#this.GUID#" type="EXCLUSIVE" timeout="5" throwontimeout="false">
			<cfif StructKeyExists(this.Cache,Arguments.Key)>
				<cfset StructDelete(this.Cache,Arguments.Key)>
				<cfloop from="#ArrayLen(this.History)#" to="1" index="i" step="-1">
					<cfif this.History[i] EQ Arguments.Key>
						<cfset ArrayDeleteAt(this.History,i)>
					</cfif>
				</cfloop>
			</cfif>
			<cfset ret=ArrayLen(this.History)>
		</cflock>
		<cfreturn ret>
	</cffunction>
</cfcomponent>